/*
 * Copyright 2012 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @fileoverview provide functions to retrieve the data from the API and
 * visualize the chart.
 * @author silvano.luciani@gmail.com (Silvano Luciani)
 */

goog.require('goog.date.Date');
goog.require('goog.date.DateRange');
goog.require('goog.dom');
goog.require('goog.dom.classes');
goog.require('goog.i18n.DateTimeFormat');
goog.require('goog.i18n.DateTimeParse');
goog.require('goog.i18n.currency');

/**
 * Loads the API client, makes the request to the API, prepare and visualize
 * the data.
 */
function makeApiCall() {
  gapi.client.load('adsense', 'v1.2', function() {
    var requestParams = getRequestParams();
    var request = gapi.client.adsense.reports.generate(requestParams);
    request.execute(function(report) {
      var currencySign = goog.i18n.currency
          .getPortableCurrencySign(report.headers[1].currency);
      var dt = new google.visualization.DataTable();
      addTableHeaders(dt, report);
      addTableRows(dt, report, currencySign);
      var chart = getChartWrapper();
      chart.getOptions().vAxis.title = currencySign;
      chart.setDataTable(dt);
      setMonthView(chart);
      google.visualization.events.addListener(chart, 'select',
          function() {setWeekView(chart);});
      var zoomOutButton = goog.dom.getElement('zoomOutButton');
      goog.events.listen(zoomOutButton, 'click',
          function() {setMonthView(chart);});
    });
  });
}

/**
 * Determines start and end date and return the parameters for our request.
 *
 * @return {Object} the parameters for our request.
 */
function getRequestParams() {
  var currentMonth = new goog.date.DateRange.thisMonth();
  var reportDateFormat = new goog.i18n.DateTimeFormat('yyyy-MM-dd');
  var startDate = reportDateFormat.format(currentMonth.getStartDate());
  var endDate = reportDateFormat.format(currentMonth.getEndDate());
  return {
    'startDate': startDate,
    'endDate': endDate,
    'metric': ['EARNINGS', 'PAGE_VIEWS_RPM', 'AD_REQUESTS_RPM'],
    'dimension': ['DATE']
  };
}

/**
 * Defines the columns for our DataTable.
 *
 * @param {google.visualization.DataTable} dt the data table containing our
 *     data.
 * @param {Object} report the response of the API.
 */
function addTableHeaders(dt, report) {
  dt.addColumn('string', report.headers[0].name);
  dt.addColumn('number', 'Earnings');
  dt.addColumn({
    'type': 'string',
    'role': 'tooltip'
  });
  dt.addColumn('number', 'Page Views RPM');
  dt.addColumn({
    'type': 'string',
    'role': 'tooltip'
  });
  dt.addColumn('number', 'Ad Request RPM');
  dt.addColumn({
    'type': 'string',
    'role': 'tooltip'
  });
  dt.addColumn({
    'type': 'boolean',
    'role': 'certainty'
  });
}

/**
 * Extract result rows from the response and adds the properly formatted values
 * to our data table.
 *
 * @param {google.visualization.DataTable} dt the data table containing our
 *     data.
 * @param {Object} report the response of the API.
 * @param {string} currencySign the currency symbol to use.
 */
function addTableRows(dt, report, currencySign) {
  var dateParser = new goog.i18n.DateTimeParse('yyyy-MM-dd');
  var monthIterator = new goog.date.DateRange.thisMonth().iterator();
  var today = new goog.date.Date();
  var iterate = true;
  var currentIndex = 0;
  var currentDay;
  var rows = report.rows;

  while (iterate) {
    try {
      currentDay = monthIterator.next();
      var reportRow = rows[currentIndex];
      var reportRowDate = new goog.date.Date();
      dateParser.parse(reportRow[0], reportRowDate);
      if (currentDay.getDate() > today.getDate()) {
        // future date
        dt.addRow(formatRow(currentDay, [0, 0, 0, 0], false, currencySign));
      } else if (goog.date.isSameDay(currentDay, reportRowDate) &&
          currentIndex < rows.length) {
        // date found in the report
        var certainty = currentDay.getDate() != today.getDate();
        dt.addRow(formatRow(currentDay, reportRow, certainty, currencySign));
        currentIndex++;
      } else {
        // date not found in the report
        dt.addRow(formatRow(currentDay, [0, 0, 0, 0], true, currencySign));
      }
    } catch (err) {
      iterate = false;
    }
  }
}

/**
 * Formats a row of data returned from the API into a row for the chart data
 * table.
 *
 * @param {goog.date.Date} day the date for the row.
 * @param {Array} reportRow the values for the metrics.
 * @param {boolean} certainty true if the measurement is certain,
 *     false otherwise.
 * @param {string} currencySign the currency symbol to use.
 * @return {Array} the row to add to the data table.
 */
function formatRow(day, reportRow, certainty, currencySign) {
  var dayOfTheWeekFormatter = new goog.i18n.DateTimeFormat('EEEE');
  var dayOfTheWeek = dayOfTheWeekFormatter.format(day);
  var dayString = day.getDate().toString();
  var earnings = parseInt(reportRow[1]);
  var earningsTooltip = dayOfTheWeek + ' ' + dayString + '\n Earnings: ' +
      earnings + ' ' + currencySign;
  var pageViewsRPM = parseInt(reportRow[2]);
  var pageViewsRPMTooltip = dayOfTheWeek + ' ' + dayString +
      '\n Page Views RPM: ' + pageViewsRPM + ' ' + currencySign;
  var adRequestsRPM = parseInt(reportRow[3]);
  var adRequestsRPMTooltip = dayOfTheWeek + ' ' + dayString +
      '\n Ad request RPM: ' + adRequestsRPM + ' ' + currencySign;
  return [dayString, earnings, earningsTooltip, pageViewsRPM,
      pageViewsRPMTooltip, adRequestsRPM, adRequestsRPMTooltip, certainty];
}

/**
 * Creates the chart wrapper for our chart.
 *
 * @return {google.visualization.ChartWrapper} the wrapper for our chart.
 */
function getChartWrapper() {
  return new google.visualization.ChartWrapper({
    'chartType': 'ColumnChart',
    'containerId': 'chartDiv',
    'options': {
      'width': 700,
      'height': 300,
      'hAxis': {
        'title': 'Day',
        'viewWindow': {}
      },
      'vAxis': {},
      'animation': {
        'duration': 1000,
        'easing': 'in'
      },
      'legend': 'top'
    }
  });
}

/**
 * Sets view window, data view and UI elements for the month view and then
 * draws the chart.
 * @param {!google.visualization.ChartWrapper} chart the target chart.
 */
function setMonthView(chart) {
  var options = chart.getOptions();
  options.hAxis.showTextEvery = 7;
  options.hAxis.viewWindow.min = 0;
  var lastOfTheMonth = goog.date.DateRange.thisMonth().getEndDate();
  options.hAxis.viewWindow.max = lastOfTheMonth.getDate();
  var zoomOutButton = goog.dom.getElement('zoomOutButton');
  goog.dom.classes.addRemove(zoomOutButton, 'active', 'inactive');
  chart.setView({
    'columns': [0, 1, 2, 7]
  });
  chart.draw();
}

/**
 * Sets view window, data view and UI elements for the week view and then draws
 * the chart.
 * @param {!google.visualization.ChartWrapper} chart the target chart.
 */
function setWeekView(chart) {
  var options = chart.getOptions();
  var selectedPoint = chart.getChart().getSelection()[0];
  var center = selectedPoint.row;
  options.hAxis.viewWindow.min = center - 3;
  options.hAxis.viewWindow.max = center + 4;
  options.hAxis.showTextEvery = 1;
  chart.setView({
    'columns': [0, 1, 2, 7, 3, 4, 7, 5, 6, 7]
  });
  chart.draw();
  var zoomOutButton = goog.dom.getElement('zoomOutButton');
  goog.dom.classes.addRemove(zoomOutButton, 'inactive', 'active');
}

